package ru.fadeev.crammer.ui.window;

import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import java.util.Random;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableModel;

import ru.fadeev.crammer.GFIndicesStorage;
import ru.fadeev.crammer.Settings;
import ru.fadeev.crammer.TestManager;
import ru.fadeev.crammer.Utils;
import ru.fadeev.crammer.data.DictionariesManager;
import ru.fadeev.crammer.data.Dictionary;
import ru.fadeev.crammer.data.Sheet;
import ru.fadeev.crammer.data.WordRecord;
import ru.fadeev.crammer.data.ThroughWordIndex;
import ru.fadeev.crammer.ui.ArrowOptionPane;
import ru.fadeev.crammer.ui.CrammerToolbarButton;
import ru.fadeev.crammer.ui.LimitedPlainDocument;
import ru.fadeev.crammer.ui.TableTextFieldFactory;
import ru.fadeev.crammer.ui.TransTextField;


/**
 * TestCrammingDialog class provides GUI for transcription test.
 * @author Konstantin Fadeyev
 *
 */
public class TestTranscriptionDialog extends JDialog {
	// Constants
	private static KeyStroke KS_CHECK_ALL_WORDS = 
			KeyStroke.getKeyStroke(KeyEvent.VK_F5, InputEvent.CTRL_MASK);
	private static KeyStroke KS_CHECK_WORD = 
			KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0);	
    private static Color RIGHT_COLOR = new Color(210,255,210);;
    private static Color SELECTION_COLOR = new Color(220,220,255);;
    private static Color SELECTION_RIGHT_COLOR = new Color(200,245,200);
    private static Color SELECTION_WRONG_COLOR = new Color(245,200,200);
    private static Color WRONG_COLOR = new Color(255,210,210);
	
   	
	protected JWindow promptWindow;
	protected Point windowLocation;
    // UI Components
	private JPanel mainPanel;	
    private JToolBar toolBar;
    private JButton editWordButton;
    private JButton checkWordButton;

	
	private JButton checkAllWordsButton;
	private JButton showTransPromptButton;
    private JScrollPane wordsScrollPane;
	
    private JTable wordsTable;
	private TestTranscriptionTableModel wordsTableModel;
	private JPopupMenu wordsPopupMenu;
	private JMenuItem wordsPopupEditWordItem;
	
    private JMenuItem wordsPopupCheckWordItem;
    
    private JMenuItem wordsPopupCheckAllWordsItem;
    private JPanel bottomPanel;
    
    private JPanel remainPanel;   
  	private JLabel remainLabel;
  	private JPanel buttonsPanel;
    
    private JButton terminateButton;
    private JButton nextButton;
    
    
  	// User fields
    
    /**
	 * Vector containing currently shown words and related information
	 */
    private Vector<TestTranscriptionRecord> currentWords; 
	private DictionariesManager dictionariesManager;
	
	/**
	 * All words for test gathered in one array
	 */
    private Vector<WordRecord> heap; 
    
    /**
     * Vector of word indices to keep track of word's place in dictionary
     */
    private Vector<ThroughWordIndex> heapIndices;  
    private Random random;   
  	private GFIndicesStorage storage;

  	
  	/**
  	 * Constructs TestTranscriptionDialog and prepares data for test
  	 * @param owner parent window
  	 * @param dictionariesManager object of DictionariesManager
  	 * @param storage object of GFIndicesStorage
  	 */
    public TestTranscriptionDialog(JFrame owner, 
    		DictionariesManager dictionariesManager, GFIndicesStorage storage) {
    	super(owner,true);
      
    	this.dictionariesManager = dictionariesManager;
        this.storage = storage;
        
    	random = new Random(System.currentTimeMillis());
    	heap = new Vector<WordRecord>();
        heapIndices = new Vector<ThroughWordIndex>();
        currentWords = new Vector<TestTranscriptionRecord>();
        
        initComponents();
        placeComponents();
        
         
        // Setting up window size. Initial window height is set depending 
        // on shown table rows number. 
        int rowsNumber = Settings.getInt("transcriptionNumberOfLines");
        int windowHeight = 119 + rowsNumber * wordsTable.getRowHeight();
              
    	int x = Settings.getInt("testTranscriptionDialogX");
    	int y = Settings.getInt("testTranscriptionDialogY");
    	int w = Settings.getInt("testTranscriptionDialogW");
        if(x<0 || y<0 || w<0) {
        	Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        	setSize(screenSize.width *2/3, windowHeight);
            setLocation(screenSize.width/6, (screenSize.height - windowHeight)/3);
        } else {
        	setSize(w, windowHeight);
        	setLocation(x, y);        	
        }
        
        initTransPrompt();
        addComponentListener(   		
        		new ComponentAdapter() {       			
        			public void componentMoved(ComponentEvent e) {
        				Point newLoc = getLocation();
       					int newPromptX = promptWindow.getX() + newLoc.x - windowLocation.x;
       					int newPromptY = promptWindow.getY() + newLoc.y - windowLocation.y;
       					promptWindow.setLocation(newPromptX, newPromptY);
        		    	windowLocation = newLoc;
        		    }
        		});
        
        setTitle("Transcription");
        
        fillCurrentHeap();
        nextAction();
        refreshWordsButtons();
    }

    
    /**
     * Initializes TranscriptionPromptWindow (map that matches transcription 
     * symbols and keyboard keys)
     */
    public void initTransPrompt() {
    	promptWindow = new TranscriptionPromptWindow(this);
    	
    	int x = Settings.getInt("testPromptWindowX");
     	int y = Settings.getInt("testPromptWindowY");
     	if(x < 0 || y < 0) {
     		promptWindow.setLocation(getX() + 450, getY() + 10);
     	} else {
     		promptWindow.setLocation(x, y);
     	}
     	promptWindow.setVisible(Settings.getBoolean("showPromptWindow"));
    }
  
    
    /**
  	 * Enable/disable toolbars buttons depending on selected words.
  	 */
    public void refreshWordsButtons() {
    	int index = wordsTable.getSelectedRow();
    	boolean enableButton = (index >=0) && (index<currentWords.size()); 
    	editWordButton.setEnabled(enableButton);
    	checkWordButton.setEnabled(enableButton);
    	
    	wordsPopupEditWordItem.setEnabled(enableButton);
    	wordsPopupCheckWordItem.setEnabled(enableButton);
    }
    
    
    /**
     * Overwritten, so it saves window location when dialog is closed
     */
    public void setVisible(boolean v) {
    	if(v == false) {
	    	Settings.setInt("testTranscriptionDialogX", getX());
	    	Settings.setInt("testTranscriptionDialogY", getY());
	    	Settings.setInt("testTranscriptionDialogW", getWidth());
	    	Settings.setInt("testPromptWindowX", promptWindow.getX());
	    	Settings.setInt("testPromptWindowY", promptWindow.getY());
	    	Settings.setBoolean("showPromptWindow", promptWindow.isVisible());

    	}
    	windowLocation = getLocation();
    	super.setVisible(v);
    }
    
    
    /**
     * Checks test results for all current words
     */
    private void checkAllResults() {
    	int rowIndex = wordsTable.getSelectedRow();
    	int columnIndex = wordsTable.getSelectedColumn();  
        for(int i=0; i<currentWords.size(); i++) {
            checkTestResult(i);
        }
        if(rowIndex >=0) {
        	wordsTable.setRowSelectionInterval(rowIndex, rowIndex);
        }
        if(columnIndex >=0) {
        	wordsTable.setColumnSelectionInterval(columnIndex, columnIndex);
        }
    }
 
  
    /**
     * Checks test result for currently selected word 
     */
    private void checkCurrentTestResult() {
    	int rowIndex = wordsTable.getSelectedRow();
    	int columnIndex = wordsTable.getSelectedColumn();  
    	checkTestResult(rowIndex);
    	wordsTable.setRowSelectionInterval(rowIndex, rowIndex);
        if(columnIndex >=0) {
        	wordsTable.setColumnSelectionInterval(columnIndex, columnIndex);
        }
    }   

    
    /**
     * Checks test result for word specified by i
     * @param i index of word to check test result
     */
    private void checkTestResult(int i) {
    	Utils.finishTableEditing(wordsTable);
        if(i >= currentWords.size() || i < 0)
            return;
        TestTranscriptionRecord record = (TestTranscriptionRecord)currentWords.elementAt(i);        
        
        String userAnswer = record.userAnswer;
        ThroughWordIndex wordIndex = record.wordIndex;
        
        Dictionary dictionary = 
        	dictionariesManager.getDictionary(wordIndex.getDictIndex());
		Sheet sheet = dictionary.getSheet(wordIndex.getSheetIndex());
        WordRecord word = sheet.getWordRecord(wordIndex.getWordIndex());
        int checkResult = TestTranscriptionRecord.UNKNOWN;
        if(userAnswer.trim().equals(word.getTranscription().trim())) {
           	checkResult = TestTranscriptionRecord.RIGHT;
        } else {
           	checkResult = TestTranscriptionRecord.WRONG;
        }
        
        if(record.checkResult == TestTranscriptionRecord.UNKNOWN) {
        	record.checkResult = checkResult;
        	boolean testSuccessful = (checkResult == TestTranscriptionRecord.RIGHT);
        	int testType = TestManager.TRANSCRIPTION;
        	word.addHistoryRecord(testType, testSuccessful);
        	word.refreshNeededToTest(testType, wordIndex.getDictIndex(), 
        			wordIndex.getSheetIndex());
        }
        
        record.showAnswer = true;
        wordsTableModel.fireTableDataChanged();
    }


    /**
     * Launches edit word dialog for currently selected word
     */
    private void editWord() {
		int index = wordsTable.getSelectedRow();
		int columnIndex = wordsTable.getSelectedColumn();
		if(index < 0 || index >= currentWords.size()) {
			return;
		}
		
		TestTranscriptionRecord currentRecord = 
					(TestTranscriptionRecord)currentWords.elementAt(index);
		WordRecord wordCopy = new WordRecord();
		wordCopy.copy(currentRecord.wordRecord);
    	
    	EditWordDialog dialog = 
    		new EditWordDialog(this, wordCopy);
    	dialog.setVisible(true);
    	
    	if(dialog.getPressedButton() == EditWordDialog.BTN_OK) {
    		int dictionaryIndex = currentRecord.wordIndex.getDictIndex();
    		int sheetIndex = currentRecord.wordIndex.getSheetIndex();
    		Dictionary dictionary = dictionariesManager.getDictionary(
    				dictionaryIndex);
    		Sheet sheet = dictionary.getSheet(sheetIndex);
    		sheet.updateWordRecord(wordCopy, currentRecord.wordIndex.getWordIndex(), 
    				storage);
    		currentRecord.wordRecord.copy(wordCopy);
    		
    		wordsTableModel.fireTableDataChanged();
    		wordsTable.setRowSelectionInterval(index, index);
            if(columnIndex >=0) {
            	wordsTable.setColumnSelectionInterval(columnIndex, columnIndex);
            }
    	}    
	}
    
    
    /**
     * Gathers all words for test in one array called heap. Then words
     * are picked up from heap randomly and presented for test.
     */
    private void fillCurrentHeap() {
        heap.removeAllElements();
        heapIndices.removeAllElements();
        dictionariesManager.startTestWordsIteration();
        while(dictionariesManager.hasNextTestWord(TestManager.TRANSCRIPTION)) {
			WordRecord word = dictionariesManager.getNextTestWord();
		    heap.addElement(word);
            heapIndices.addElement(dictionariesManager.getCurrentIndex());
        }
    }

    
    /**
     * Checks if heap has next word
     * @return true, if heap is not empty
     */
    private boolean hasNextWord() {
		if(heap.size()==0) {
			random.setSeed(System.currentTimeMillis());
		}
		return heap.size()!=0;
	}
        
    
    /**
     * Initializes UI Components of dialog
     */
    private void initComponents() {
    	//Main panel
    	mainPanel = new JPanel();
    	
    	//Word Buttons
    	ImageIcon editWordIcon = new ImageIcon("icons/16/editWord.png");
        editWordButton = new CrammerToolbarButton(editWordIcon, "Edit Word");
        editWordButton.addActionListener(
			    new AbstractAction() {
					public void actionPerformed(ActionEvent ev) {
			        	editWord();
			        }
			    });

        ImageIcon checkWordIcon = new ImageIcon("icons/16/checkWord.png");
        checkWordButton = new CrammerToolbarButton(checkWordIcon, 
        		"Check Word (" + Utils.keyStrokeToString(KS_CHECK_WORD) + ")");
        AbstractAction checkWordAction = 
        	new AbstractAction() {
		        public void actionPerformed(ActionEvent ev) {
		        	checkCurrentTestResult();
		        }
		    };
	    checkWordButton.addActionListener(checkWordAction);

	    checkWordButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
	    		KS_CHECK_WORD, "checkWord");
	    checkWordButton.getActionMap().put("checkWord", checkWordAction);
	    
        
        ImageIcon checkAllWordsIcon = new ImageIcon("icons/16/checkAllWords.png");
        checkAllWordsButton = new CrammerToolbarButton(checkAllWordsIcon, 
        		"Check All Words (" + Utils.keyStrokeToString(KS_CHECK_ALL_WORDS) + ")");
        AbstractAction checkAllWordsAction = 
        	new AbstractAction() {
		        public void actionPerformed(ActionEvent ev) {
		        	checkAllResults();
		        }
		    };
	    checkAllWordsButton.addActionListener(checkAllWordsAction);

	    checkAllWordsButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
	    		KS_CHECK_ALL_WORDS, "checkAllWords");
	    checkAllWordsButton.getActionMap().put("checkAllWords", checkAllWordsAction);
      	
		ImageIcon showTransPromptIcon = new ImageIcon("icons/16/showTransMap.png");
		showTransPromptButton = new CrammerToolbarButton(showTransPromptIcon, 
				"Show Transcription Prompt");     
		showTransPromptButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			        	promptWindow.setVisible(!promptWindow.isVisible());
			        }
			    });
		
		toolBar = new JToolBar(JToolBar.HORIZONTAL);
		toolBar.setFloatable(false);
        
		toolBar.add(editWordButton);
		toolBar.addSeparator();
		toolBar.add(checkWordButton);
		toolBar.add(checkAllWordsButton);
		toolBar.addSeparator();
		toolBar.add(showTransPromptButton);
        
        //Words table
        initWordsTable();
    	
    	//Popup Menu
    	initWordsPopupMenu();
    	
    	//Label 
        bottomPanel = new JPanel();
        
        remainPanel = new JPanel();
        remainLabel = new  JLabel();
        
        //Next and Terminate Buttons
        buttonsPanel = new JPanel();  
        
      	
      	terminateButton = new JButton("Terminate");
      	terminateButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			        	terminateAction();
			        }
			    });
      	
      	nextButton = new JButton("Next");
      	nextButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			        	nextAction();
			        }
			    });
      	        
        setContentPane(mainPanel);
    }
    
  	
  	/**
	 * Gets from the heap next portion of words for test (randomly). And
	 * fills test table with them.
	 */
    private void nextAction() {
    	if (thereIsUncheckedWords()) {
            int n = ArrowOptionPane.showConfirmDialog(this,
            		"There are some unchecked words.\n" +
                    "Do you really want to move on?", "Warning", 
                    JOptionPane.YES_NO_OPTION);
            if(n != JOptionPane.OK_OPTION) {
            	return;
            }    		
    	}
    	
    	Utils.finishTableEditing(wordsTable);
    	
    	currentWords.removeAllElements();
		for(int i=0; i <  Settings.getInt("transcriptionNumberOfLines"); i++) {
			if(!hasNextWord())
				break;
			int pos = random.nextInt(heap.size());
			WordRecord currentWord = (WordRecord)heap.elementAt(pos);
			ThroughWordIndex currentIndex = (ThroughWordIndex)heapIndices.elementAt(pos);
            heap.remove(pos);
            heapIndices.remove(pos);
            
            TestTranscriptionRecord record = new TestTranscriptionRecord(currentWord);
            record.wordIndex = currentIndex;
            currentWords.addElement(record);
		}
		wordsTableModel.fireTableDataChanged();
		remainLabel.setText("Remain: " + heap.size());
		nextButton.setEnabled(hasNextWord());
		
		wordsTable.setRowSelectionInterval(0, 0);
		wordsTable.setColumnSelectionInterval(1, 1);
		wordsTable.requestFocus();
	}
   
    
    /**
     * Places UI components using different layout managers
     */
  	private void placeComponents() {
    	mainPanel.setLayout(new BorderLayout());
    	mainPanel.add(toolBar, BorderLayout.NORTH);
    	mainPanel.add(wordsScrollPane, BorderLayout.CENTER);
    	mainPanel.add(bottomPanel, BorderLayout.SOUTH);
    	  	   	   	
    	bottomPanel.setPreferredSize(new Dimension(200, 40));
    	
    	bottomPanel.setLayout(new BorderLayout());
    	bottomPanel.add(remainPanel, BorderLayout.WEST);
    	bottomPanel.add(buttonsPanel, BorderLayout.EAST);
    	
    	remainPanel.setPreferredSize(new Dimension(100, 40));
    	
    	remainPanel.setLayout(null);
    	remainPanel.add(remainLabel);
    	
    	remainLabel.setBounds(10, 10, 70, 20);
    	
    	buttonsPanel.setPreferredSize(new Dimension(210, 40));
    	buttonsPanel.setLayout(null);
    	buttonsPanel.add(nextButton);
    	buttonsPanel.add(terminateButton);
    	
    	nextButton.setBounds(10, 10, 90, 20);
    	terminateButton.setBounds(110, 10, 90, 20);    	
  	}

    
    /**
     * Terminate button action handler. Finishes test.
     */
    private void terminateAction() {
    	if (thereIsUncheckedWords()) {
            int n = ArrowOptionPane.showConfirmDialog(this,
            		"There are some unchecked words.\n" +
                    "Do you really want to end test?", "Warning", 
                    JOptionPane.YES_NO_OPTION);
            if(n != JOptionPane.OK_OPTION) {
            	return;
            }    		
    	}
    	
    	setVisible(false);
    }
	
    
    /**
     * Checkes if there are any unchecked words in currently shown 
     * words list 
     * @return true, if there are any unchecked words
     */
    private boolean thereIsUncheckedWords() {
        for(int i=0; i<currentWords.size(); i++) {
            TestTranscriptionRecord record = currentWords.elementAt(i);
            if(record.checkResult == TestTranscriptionRecord.UNKNOWN) {
            	return true;
            }
        }
        return false;
    }   
    
    /**
     * Initializes popup menu for wordsTable
     */
    private void initWordsPopupMenu() {
    	wordsPopupMenu = new JPopupMenu();
    	wordsPopupEditWordItem = new JMenuItem("Edit Word");
    	wordsPopupCheckWordItem = new JMenuItem("Check Word");
    	wordsPopupCheckWordItem.setAccelerator(KS_CHECK_WORD);
    	wordsPopupCheckAllWordsItem = new JMenuItem("Check All Words");
    	wordsPopupCheckAllWordsItem.setAccelerator(KS_CHECK_ALL_WORDS);
		
    	wordsPopupMenu.add(wordsPopupEditWordItem);
    	wordsPopupMenu.addSeparator();
    	wordsPopupMenu.add(wordsPopupCheckWordItem);
    	wordsPopupMenu.add(wordsPopupCheckAllWordsItem);
    	
    	wordsPopupEditWordItem.addActionListener(new AbstractAction() {
					public void actionPerformed(ActionEvent e) {
						wordsPopupMenu.setVisible(false);
						editWord();
					}
				});
		
    	wordsPopupCheckWordItem.addActionListener(new AbstractAction() {
					public void actionPerformed(ActionEvent e) {
						wordsPopupMenu.setVisible(false);
						checkCurrentTestResult();
					}
				});
    	
    	wordsPopupCheckAllWordsItem.addActionListener(new AbstractAction() {
					public void actionPerformed(ActionEvent e) {
						wordsPopupMenu.setVisible(false);
						checkAllResults();
					}
				});
    }
    
    
    /**
     * Initializes wordsTable
     */
    private void initWordsTable()
    {
    	wordsTableModel = new TestTranscriptionTableModel(currentWords);    
    	wordsTable = new JTable(wordsTableModel);
    	wordsTable.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
    	wordsTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);

    	wordsTable.getSelectionModel().setSelectionMode(
    			ListSelectionModel.SINGLE_SELECTION);
    	
        TestTranscriptionSelectionListener wordsTableListener 
					= new TestTranscriptionSelectionListener(this);
        wordsTable.getSelectionModel().addListSelectionListener(wordsTableListener);
        wordsTable.getColumnModel().getSelectionModel()
							.addListSelectionListener(wordsTableListener);

        final JTextField textField = 
        	TableTextFieldFactory.createTableTextField(new TransTextField());
    	LimitedPlainDocument document = 
			new LimitedPlainDocument(Settings.TRANSCRIPTION_MAX_LENGTH);
    	textField.setDocument(document);
        TestTranscriptionCellEditor testEditor = 
        	new TestTranscriptionCellEditor(textField, currentWords);
        textField.addMouseListener(
				new MouseAdapter() {
					public void mouseClicked(MouseEvent ev) {
						wordsPopupMenu.setVisible(false);
						if(ev.getButton() == MouseEvent.BUTTON3) {
							Point textFieldLoc = textField.getLocationOnScreen();
							Point tableFieldLoc = wordsTable.getLocationOnScreen();
							int tableX = textFieldLoc.x + ev.getPoint().x - tableFieldLoc.x;
							int tableY = textFieldLoc.y + ev.getPoint().y - tableFieldLoc.y;
							Point tablePoint = new Point(tableX, tableY);
							int row = wordsTable.rowAtPoint(tablePoint);
							int column = wordsTable.columnAtPoint(tablePoint);
							if(!wordsTable.isRowSelected(row)) {
								wordsTable.clearSelection();
								wordsTable.setRowSelectionInterval(row, row);
								wordsTable.setColumnSelectionInterval(column, column);
							}
							wordsPopupMenu.show(textField, ev.getPoint().x, ev.getPoint().y);
						}
					}
				});
        
        wordsTable.setDefaultEditor(String.class, testEditor);
        
    	TestTranscriptionCellRenderer cellRenderer = 
    		new TestTranscriptionCellRenderer(currentWords);
    	wordsTable.setDefaultRenderer(String.class, cellRenderer);
    	wordsTable.setSelectionForeground(Color.BLACK);
    	
    	wordsTable.getTableHeader().setReorderingAllowed(false);
    	
		wordsTable.getColumnModel().getColumn(0).setPreferredWidth(100);
    	wordsTable.getColumnModel().getColumn(1).setPreferredWidth(170);
    	wordsTable.getColumnModel().getColumn(2).setPreferredWidth(150);
    	 	
    	wordsTable.addMouseListener(
				new MouseAdapter() {
					public void mouseClicked(MouseEvent ev) {
						wordsPopupMenu.setVisible(false);
						if(ev.getButton() == MouseEvent.BUTTON3) {
							int row = wordsTable.rowAtPoint(ev.getPoint());
							wordsTable.requestFocus();
							if(!wordsTable.isRowSelected(row)) {
								wordsTable.clearSelection();
								wordsTable.setRowSelectionInterval(row, row);
							}
							wordsPopupMenu.show(wordsTable, ev.getPoint().x, ev.getPoint().y);
						}
					}
				});
    	 	
    	wordsScrollPane = new JScrollPane(wordsTable);    	
    }
    
   
    /**
     * TestTranscriptionCellEditor class represents cell editor for words table 
     * in TestTranscriptionDialog
     * @author Konstantin Fadeyev
     */
    private class TestTranscriptionCellEditor extends AbstractCellEditor
			implements TableCellEditor {
    
    	/**
    	 * Vector of TestTranscriptionRecord containing currently shown words 
    	 * and related information
    	 */
        private Vector<TestTranscriptionRecord> currentWords; 
        private JTextField transcriptionTextField;

        
        public TestTranscriptionCellEditor(JTextField transcriptionTextField, 
        		Vector<TestTranscriptionRecord> currentWords) {       	
        	this.transcriptionTextField = transcriptionTextField;
        	this.currentWords = currentWords;
        }
      
        public Object getCellEditorValue() {
        		return transcriptionTextField.getText();
        }
        
        public Component getTableCellEditorComponent(JTable table,Object value,
        						boolean isSelected, int row, int column) {
        	transcriptionTextField.setText((String)value);
            if(column!=1 || row >= currentWords.size()) {
            	transcriptionTextField.setBackground(Color.white);
            } else {
            	TestTranscriptionRecord record = 
    				(TestTranscriptionRecord)currentWords.elementAt(row);
                switch(record.checkResult) {
                case TestTranscriptionRecord.UNKNOWN:
                	transcriptionTextField.setBackground(Color.white);
                    break;
                case TestTranscriptionRecord.RIGHT:
                	transcriptionTextField.setBackground(RIGHT_COLOR);
                    break;
                case TestTranscriptionRecord.WRONG:
                	transcriptionTextField.setBackground(WRONG_COLOR);
                }
            }    	
            return transcriptionTextField;
        }
    }
    
    
    /**
     * TestTranscriptionCellRenderer class represents cell renderer 
     * for words table in TestTranscriptionDialog
     * @author Konstantin Fadeyev
     *
     */
    private class TestTranscriptionCellRenderer extends DefaultTableCellRenderer {
    	
    	/**
    	 * Vector of TestTranscriptionRecord containing currently shown words 
    	 * and related information
    	 */
        private Vector<TestTranscriptionRecord> currentWords; 	
        private Font defaultFont; 
        private Font transcriptionFont; 
    	

        public TestTranscriptionCellRenderer(
        		Vector<TestTranscriptionRecord> currentWords) {
        	this.currentWords = currentWords;
        	defaultFont = (new JTextField()).getFont();
        	defaultFont = (new JTextField()).getFont();
        	transcriptionFont = new Font("LucidaSans", 
        			defaultFont.getStyle(), defaultFont.getSize());
        }

        
        public Component getTableCellRendererComponent(JTable table, 
        		Object value, boolean isSelected, boolean hasFocus, 
        		int row, int column) {
            Component cell = super.getTableCellRendererComponent(table, value, 
            		isSelected, hasFocus, row, column);
            cell.setForeground(Color.black);
            if(column!=1 || row >= currentWords.size()) {
                cell.setBackground(Color.white);
                if(isSelected)
                    cell.setBackground(SELECTION_COLOR);
                if(hasFocus)
                    cell.setBackground(Color.white);
            } else {
            	TestTranscriptionRecord record = 
    				(TestTranscriptionRecord)currentWords.elementAt(row);
                switch(record.checkResult) {
                case TestTranscriptionRecord.UNKNOWN:
                    cell.setBackground(Color.white);
                    if(isSelected)
                        cell.setBackground(SELECTION_COLOR);
                    if(hasFocus)
                        cell.setBackground(Color.white);
                    break;
                case TestTranscriptionRecord.RIGHT:
                    cell.setBackground(RIGHT_COLOR);
                    if(isSelected)
                        cell.setBackground(SELECTION_RIGHT_COLOR);
                    if(hasFocus)
                        cell.setBackground(RIGHT_COLOR);
                    break;
                case TestTranscriptionRecord.WRONG:
                    cell.setBackground(WRONG_COLOR);
                    if(isSelected)
                        cell.setBackground(SELECTION_WRONG_COLOR);
                    if(hasFocus)
                        cell.setBackground(WRONG_COLOR);
                }
            }
            if(column == 1 || column == 2) {
            	cell.setFont(transcriptionFont);
            } else {
            	cell.setFont(defaultFont);
            }
            if(hasFocus && isSelected) {
                TableModel tblModel = table.getModel();
                if(tblModel.isCellEditable(row, column)) {
                    table.editCellAt(row, column);
                    table.getEditorComponent().requestFocus();
                }
            }
            return cell;
        }
    }
    
    
    /**
     * TestTranscriptionRecord class is used to keep information about 
     * shown word (word text, user answer, is word checked or not and etc.)
     * @author Konstantin Fadeyev
     *
     */
    private class TestTranscriptionRecord {
    	public static final int UNKNOWN = 0;
    	
    	public static final int RIGHT = 1;
    	
    	public static final int WRONG = 2;
    	public WordRecord wordRecord;
    	/**
    	 * Index of word to keep track of word's place in dictionary
    	 */
    	public ThroughWordIndex wordIndex;   
    	
    	public String userAnswer;
    	public boolean showAnswer;
    	public int checkResult;
    	
    	public TestTranscriptionRecord(WordRecord w) {
    		wordRecord = w;
    		showAnswer = false;
    		checkResult = UNKNOWN;
    		userAnswer = "";
    	}
    }
    
    
    /**
     * TestTranscriptionSelectionListener class represents selection listener 
     * for words table in TestTranscriptionDialog
     * @author Konstantin Fadeyev
     *
     */
    private class TestTranscriptionSelectionListener  implements ListSelectionListener {
    	TestTranscriptionDialog dialog;
    	
    	public TestTranscriptionSelectionListener(TestTranscriptionDialog d) {
    	    dialog = d;
    	}
    	
    	public void valueChanged(ListSelectionEvent e) {
    		dialog.refreshWordsButtons();
    	}
    }
    
    
    /**
     * TestTranscriptionTableModel class represents table model
     * for words table in TestTranscriptionDialog
     * @author Konstantin Fadeyev
     *
     */
    private class TestTranscriptionTableModel  extends AbstractTableModel {
    	
    	/**
    	 * Vector of TestTranscriptionRecord containing currently shown words 
    	 * and related information
    	 */
        private Vector<TestTranscriptionRecord> currentWords; 
           
    	private int tableSize;

    	
    	public TestTranscriptionTableModel(
    			Vector<TestTranscriptionRecord> currentWords)	{
    		super();
    		this.currentWords = currentWords;
    		tableSize = Settings.getInt("transcriptionNumberOfLines");
    	}

    	public Class<?> getColumnClass(int c) {
            return getValueAt(0, c).getClass();
        }

    	public int getColumnCount() {
    		return 3;
    	}

    	public String getColumnName(int num) {
    		switch(num) {
    		case 0:
    			return "Word";
    		case 1:
    			return "Your transcription";
    		default:
    			return "Right transcription";
    		}
    	}

        public int getRowCount() {
    	    return tableSize;
    	}

    	public Object getValueAt(int row, int column) {
    		switch(column) {
    		case 0:
    			if(row < currentWords.size()) {
    				TestTranscriptionRecord record = 
    					(TestTranscriptionRecord)currentWords.elementAt(row);					
    				return record.wordRecord.getWord();
    			} else {
    				return "";
    			}
    		case 1:
    			if(row < currentWords.size()) {
    				TestTranscriptionRecord record = 
    					(TestTranscriptionRecord)currentWords.elementAt(row);
    				return record.userAnswer;
    			} else {
    				return "";
    			}
            default:
    			if(row < currentWords.size()) {
    				TestTranscriptionRecord record = 
    					(TestTranscriptionRecord)currentWords.elementAt(row);
                    if(record.showAnswer)
                    	return record.wordRecord.getTranscription();
                    else
                        return "";
       			} else {
    				return "";
    			}
    		}
    	}
    	
    	public boolean isCellEditable(int rowIndex, int columnIndex) {
    		switch(columnIndex) {
    		case 0:
    			return false;
    		case 1:
    			if(rowIndex<currentWords.size())
    				return true;
    			else
    				return false;
    		default:
    			return false;
    		}
        }

        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
    		if(columnIndex!=1)
    			return;
    		
            if(rowIndex>=currentWords.size())
    	        return;
            
            TestTranscriptionRecord record = 
    			(TestTranscriptionRecord)currentWords.elementAt(rowIndex);
            record.userAnswer = (String)aValue;
    	}
    }
}
